package com.intretech.umsin.oss.util.ftppool;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

/**
 * @version V1.0
 * @ClassName: FtpClientTemplate
 * @Description: FtpClientTemplate 服务实现
 * @author: 李启联
 * @date: 2022-04-25 15:15
 * @Copyright: Copyright (c) 2021
 */
@Slf4j
public class FtpClientTemplate {

    private FtpClientPool ftpClientPool;

    public FtpClientTemplate(FtpClientPool ftpClientPool) {
        this.ftpClientPool = ftpClientPool;
    }

    /**
     * 上传文件
     * @param input 文件输入流
     * @param dest ftp 目标路径+文件
     * @throws Exception
     */
    public void upload(InputStream input, String dest) throws Exception {
        FTPClient client = null;
        try {
            client = ftpClientPool.borrowObject();
            // 验证FTP服务器是否登录成功
            int replyCode = client.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                log.warn("ftpServer refused connection, replyCode:{}", replyCode);
            }
            String pathName = "",fileName=dest;
            if(dest.lastIndexOf("/")>0) {
                pathName = dest.substring(0, dest.lastIndexOf("/"));
                fileName = dest.substring(dest.lastIndexOf("/") + 1);
            }
            //mkdirs(pathName);
            mkdirs(client,pathName);
            // 改变工作路径
            client.changeWorkingDirectory(pathName);
            client.storeFile(fileName, input);
        } catch (Exception e) {
            log.error("upload  file  failed,异常", e);
            throw e;
        } finally {
            //IOUtils.closeQuietly(input);
            //将对象放回池中
            ftpClientPool.returnObject(client);
        }
    }



    /**
     * 在ftp服务器上创建目录,(值得注意的是：ftpClient 无法一次性创建多级目录,则需要人为逐级生成目录。)
     * @param pathName 目录路径 (如：/A/B/C)
     * @throws Exception
     */
    public void mkdirs(String pathName) throws Exception {
        try {
            FTPClient client = ftpClientPool.borrowObject();

            /*该部分为逐级创建*/
            String[] split = pathName.split("/");

            for (String str : split) {
                if(StringUtils.isBlank(str)) {
                    continue;
                }
                if (!client.changeWorkingDirectory(str)) {
                    boolean makeDirectory = client.makeDirectory(str);
                    boolean changeWorkingDirectory = client.changeWorkingDirectory(str);
                }
            }
        } catch (Exception e) {
            log.error("mkdirs {}  failed,异常", pathName, e);
            throw e;
        }
    }

    /**
     * 在ftp服务器上创建目录,(值得注意的是：ftpClient 无法一次性创建多级目录,则需要人为逐级生成目录。)
     * @param ftpClient
     * @param pathName 目录路径 (如：/A/B/C)
     * @throws Exception
     */
    public void mkdirs(FTPClient ftpClient, String pathName) throws Exception {
        try {
            ftpClient.changeWorkingDirectory(ftpClientPool.getClientFactory().getConfig().getWorkDir());
            /*该部分为逐级创建*/
            String[] split = pathName.split("/");

            for (String str : split) {
                if(StringUtils.isBlank(str)) {
                    continue;
                }
                if (!ftpClient.changeWorkingDirectory(str)) {
                    boolean makeDirectory = ftpClient.makeDirectory(str);
                    boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(str);
                }
            }
        } catch (Exception e) {
            log.error("mkdirs {}  failed,异常", pathName, e);
            throw e;
        }
    }

    public byte[] download(String src) throws Exception {
        log.info("开始下载文件 文件名路径: {}",src);
        FTPClient ftpClient = null;
        InputStream in = null;
        try {
            ftpClient = ftpClientPool.borrowObject();

            ftpClient.changeWorkingDirectory(ftpClientPool.getClientFactory().getConfig().getWorkDir());

            in = ftpClient.retrieveFileStream(new String(src.getBytes(FtpConstant.GBK),FtpConstant.ISO_8859_1));

            if(in != null) {
                log.error("下载文件成功 远程文件名路径: {} : ["+src+" ]");
                return ByteUtil.inputStreamToByteArray(in);
            }else {
                log.error("下载文件失败 文件名路径: {} : ["+src+" ]");
                return null;
            }
        }catch (Exception e){
            log.error("下载文件异常 文件名路径: {} : ["+src+" ]",e);
            throw e;
        }finally{
            if (in != null) {
                in.close();
            }
            ftpClientPool.returnObject(ftpClient);
        }
    }

    /**
     * 删除指定路径下的文件
     * @param pathName
     */
    public void deleteFile(String pathName){
        FTPClient ftpClient = null;
        try {
            ftpClient = ftpClientPool.borrowObject();
            // 验证FTP服务器是否登录成功
            int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                log.warn("ftpServer refused connection, replyCode:{}", replyCode);
            }
            boolean del = ftpClient.deleteFile(pathName);
            if(!del){
                log.error("delete file {}  异常", pathName);
                throw new RuntimeException("Failed to delete file '" + pathName + "'!");
            }
        } catch (Exception e) {
            log.error("deleteFile {}  异常", pathName, e);
        }finally {
            ftpClientPool.returnObject(ftpClient);
        }

    }

    public void deleteDir(String pathName) {
        FTPClient ftpClient = null;
        try {
            ftpClient = ftpClientPool.borrowObject();
            deleteDirFile(pathName, ftpClient);
        } catch (Exception e) {
            log.error("deleteDir {}  异常", pathName, e);
        }finally {
            ftpClientPool.returnObject(ftpClient);
        }
    }

    private void deleteDirFile(String pathName, FTPClient client) throws IOException {
        FTPFile[] ftpFiles = client.listFiles(pathName);
        if (ftpFiles != null && ftpFiles.length != 0) {
            for (FTPFile ftpFile : ftpFiles) {
                if (ftpFile.isDirectory()) {
                    deleteDirFile(pathName + "/" + ftpFile.getName(), client);
                } else {
                    client.deleteFile(pathName + "/" + ftpFile.getName());
                }
            }
        }
        client.changeWorkingDirectory(pathName);
        client.changeToParentDirectory();
        boolean del = client.removeDirectory(pathName);
        if(!del){
            log.error("delete dir {}  异常", pathName);
            throw new RuntimeException("Failed to delete dir '" + pathName + "'!");
        }
    }

    public String[] ls(String pathName) {
        FTPClient ftpClient = null;
        try {
            ftpClient = ftpClientPool.borrowObject();
            FTPFile[] ftpFiles = ftpClient.listFiles(pathName);
            return Arrays.stream(ftpFiles)
                    .filter(FTPFile::isDirectory)
                    .map(FTPFile::getName)
                    .toArray(String[]::new);
        } catch (Exception e) {
            log.error("ls {}  failed,异常", pathName, e);
        }finally {
            ftpClientPool.returnObject(ftpClient);
        }
        return null;
    }


}
